/**
 * 
 */
package vn.smartware.co.framework.config;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import javax.servlet.ServletContext;

import org.apache.commons.digester.Digester;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;

import vn.smartware.co.framework.exception.FatalException;
import vn.smartware.co.framework.form.ActionForm;
import vn.smartware.co.framework.form.TemporarilyActionForm;
import vn.smartware.co.framework.validator.ActionError;
import vn.smartware.co.framework.validator.Resources;

/**
 * ActionMapping
 */
public class ActionMapping {
	
	private static Log log = LogFactory.getLog(ActionMapping.class);
	
	/**
	 * 
	 * loadMapping: 
	 * @param realPath
	 * @return SmsConfig
	 * @throws FatalException
	 */
	public static SystemConfig loadMapping(InputStream realPath) throws FatalException {
		
		SystemConfig mapping = new SystemConfig();

		Digester digester = new Digester();

		try {
			digester.push(mapping);
			
			digester.addObjectCreate("system-config/webserver/", WebServerConfig.class);
			
			digester.addSetProperties("system-config/webserver/server-property");
			
			digester.addSetNext("system-config/webserver/server-property", "setWebServer", WebServerConfig.class.getName());
			
			digester.addObjectCreate("system-config/form-beans/form-bean", FormBeansConfig.class);			
			
			digester.addSetProperties("system-config/form-beans/form-bean", "name", "name");
			
			digester.addSetNext("system-config/form-beans/form-bean", "addFormBeans", FormBeansConfig.class.getName());
			
			digester.addObjectCreate("system-config/global-exceptions/exception", GlobalExceptionsConfig.class);
			
			digester.addSetProperties("system-config/global-exceptions/exception", "type", "type");
			
			digester.addSetNext("system-config/global-exceptions/exception", "addGlobalExceptions", GlobalExceptionsConfig.class.getName());
			
			digester.addObjectCreate("system-config/action-mappings/action", ActionMappingsConfig.class);
			
			digester.addSetProperties("system-config/action-mappings/action", "name", "name");			
			
			digester.addSetProperties("system-config/action-mappings/action/args", "key", "args");

			digester.addObjectCreate("system-config/action-mappings/action/exception", ActionExceptionConfig.class);
			
			digester.addSetProperties("system-config/action-mappings/action/exception", "type", "type");
			
			digester.addSetNext("system-config/action-mappings/action/exception", "addActionException", ActionExceptionConfig.class.getName());
			
			digester.addSetNext("system-config/action-mappings/action", "addActionMappingsConfig", ActionMappingsConfig.class.getName());			

			digester.parse(realPath);
			
			log.debug("Config parse complete.");
			
		} catch (IOException e) {
			log.error("Config parse Error.", e);
			throw new FatalException("Config parse Error.", e);
		} catch (SAXException e) {
			log.error("Config parse Error.", e);
			throw new FatalException("Config parse Error.", e);
		}
		return mapping;
	}
	
	/**
	 * 
	 * setExceptionMessage: 
	 * @param form
	 * @param e
	 * @param mapping
	 * @return ActionForm
	 */
	public static ActionForm setExceptionMessage(ActionForm form, Throwable e,
			SystemConfig mapping) {
		
		form = setExceptionMessage(form, e, mapping, null);
		return form;
	}
	
	/**
	 * 
	 * setExceptionMessage: 
	 * @param form
	 * @param e
	 * @param message
	 * @return ActionForm
	 */
	public static ActionForm setExceptionMessage(ActionForm form, Throwable e, String message) {
		
		form = setExceptionMessage(form, e, null, message);
		return form;
	}
	
	/**
	 * 
	 * setExceptionMessage: 
	 * @param form
	 * @param throwable
	 * @param mapping
	 * @param message
	 * @return ActionForm
	 */
	@SuppressWarnings("rawtypes")
	public static ActionForm setExceptionMessage(ActionForm form,
			Throwable throwable, SystemConfig mapping, String message) {
		
		String errorMessage = null;
		
		if (form == null) {
			form = new TemporarilyActionForm();
		}
		
		form.setStatus(false);
		
		try {
			
			if (message == null) {
				String key = getExceptionKey(mapping, form, throwable);

				ArrayList values = mapping.getActionMappingConfig(form.getActionForm()).getArgslist();
				ActionError errorMsgObj = new ActionError(key, values.toArray());
				errorMessage = Resources.getMessage(errorMsgObj);
				
				form.setMessage(errorMessage);
				
				form.setException(throwable);
				
			} else {
			    
				form.setMessage(message);
				
				form.setException(throwable);
				
			}
			
		} catch (Exception e) {
			log.error("setExceptionMessage Exception.", e);
			e.printStackTrace();
		}
		
		return form;
	}

	/**
	 * 
	 * setExceptionMessage: 
	 * @param context
	 * @param form
	 * @param e
	 * @param mapping
	 * @return ActionForm
	 */
	public static ActionForm setExceptionMessage(ServletContext context,
			ActionForm form, Throwable e, SystemConfig mapping) {
		
		form = setExceptionMessage(context, form, e, mapping, null);
		return form;
	}
	
	/**
	 * 
	 * setExceptionMessage: 
	 * @param context
	 * @param form
	 * @param e
	 * @param message
	 * @return ActionForm
	 */
	public static ActionForm setExceptionMessage(ServletContext context,
			ActionForm form, Throwable e, String message) {
		
		form = setExceptionMessage(context, form, e, null, message);
		return form;
	}
	
	/**
	 * 
	 * setExceptionMessage: 
	 * @param context
	 * @param form
	 * @param throwable
	 * @param mapping
	 * @param message
	 * @return ActionForm
	 */
	@SuppressWarnings("rawtypes")
	public static ActionForm setExceptionMessage(ServletContext context,
			ActionForm form, Throwable throwable, SystemConfig mapping,
			String message) {
		
		String errorMessage = null;
		
		if (form == null) {
			form = new TemporarilyActionForm();
		}
		
		form.setStatus(false);
		
		try {
			
			if (message == null) {
				String key = getExceptionKey(mapping, form, throwable);

				ArrayList values = mapping.getActionMappingConfig(form.getActionForm()).getArgslist();
				ActionError errorMsgObj = new ActionError(key, values.toArray());
				errorMessage = Resources.getMessage(errorMsgObj, context);
				
				form.setMessage(errorMessage);
				
				form.setException(throwable);
				
			} else {
			    
				form.setMessage(message);
				
				form.setException(throwable);
				
			}
			
		} catch (Exception e) {
			log.error("setExceptionMessage Exception.", e);
			e.printStackTrace();
		}
		
		return form;
	}
	
	/**
	 * 
	 * getExceptionKey: 
	 * @param mapping
	 * @param form
	 * @param e
	 * @return String
	 */
	private static String getExceptionKey(SystemConfig mapping, ActionForm form, Throwable e) {
		
		String key = null;
		String cause = null;
		
		if (e.getCause() != null) {
			cause = e.getCause().toString();
		} else {
			cause = e.getClass().getName();
		}
		
		GlobalExceptionsConfig global = mapping.getGlobalExceptions(cause);
		
		if (global != null) {
			key = global.getKey();
			
		} else {
			
			ActionMappingsConfig action = mapping.getActionMappingConfig( form.getActionForm());
			if (action == null) {
				return key;
			}
			
			ActionExceptionConfig exception = action.getActionException(cause);
			
			if (exception != null) {
				key = exception.getKey();
			}
		}

		return key;
	}
}
